文章目录
  1. 1. 前言
  2. 2. 开始编码
    1. 2.1 定义注解
    2. 2.2 定义注解处理器
    3. 2.3 注册处理器服务
    4. 2.4 测试
  3. 3. 如何debug程序

[TOC]

1. 前言

在编译代码的时候,生成java的代码可以做很多事情,比如初始化各种环境(比如Butter Knife,虽然没用过),而无需手动去写各种冗余的代码。

下面准备在编译代码的时候生成如下的java文件,内容很简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package io.patamon.apt;

import java.util.ArrayList;
import java.util.List;

public class TestJavaSourceGenerate {
private static final List<String> TEST = new ArrayList();

public TestJavaSourceGenerate() {
}

public static List<String> getTest() {
return TEST;
}

static {
TEST.add("0");
TEST.add("1");
}
}

2. 开始编码

2.1 定义注解

1
2
3
4
5
6
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
@Documented
public @interface TestJavaSource {

}

2.2 定义注解处理器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
@SupportedAnnotationTypes({"io.patamon.apt.annotation.TestJavaSource"})
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class TestJavaSourceProcessor extends AbstractProcessor {

private Filer filer;

@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
this.filer = processingEnv.getFiler();
}

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (TypeElement element : annotations) {
roundEnv.getElementsAnnotatedWith(element).forEach(it -> {
generateFile("io.patamon.apt.TestJavaSourceGenerate");
});
}
return false;
}

/**
* 生成java文件
*/
private void generateFile(String path) {
BufferedWriter writer = null;
try {
// 1. 创建java源文件
JavaFileObject sourceFile = filer.createSourceFile(path);
int period = path.lastIndexOf('.');
String myPackage = period > 0 ? path.substring(0, period) : null;
String clazz = path.substring(period + 1);
// 2. 写入代码
writer = new BufferedWriter(sourceFile.openWriter());
if (myPackage != null) {
writer.write("package " + myPackage + ";\n\n");
}
writer.write("import java.util.ArrayList;\n");
writer.write("import java.util.List;\n\n");
writer.write("/** This class is generated by CustomProcessor, do not edit. */\n");
writer.write("public class " + clazz + " {\n");
writer.write(" private static final List<String> TEST;\n\n");
writer.write(" static {\n");
writer.write(" TEST = new ArrayList<>();\n\n");
writer.write(" TEST.add(\"" + 1 + "\");\n");
writer.write(" TEST.add(\"" + 2 + "\");\n");
writer.write(" }\n\n");
writer.write(" public static List<String> getTest() {\n");
writer.write(" return TEST;\n");
writer.write(" }\n\n");
writer.write("}\n");
} catch (IOException e) {
throw new RuntimeException("Could not write source for " + path, e);
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
//Silent
}
}
}
}
}

2.3 注册处理器服务

2.4 测试

1
2
3
4
5
6
7
8
@TestJavaSource
public class TestJavaSourceAnnotationDemo {

public static void main(String[] args) throws Exception {
System.out.println(TestJavaSourceGenerate.getTest());
}

}

编译代码,在工程中可以看到如下效果:

要想在代码中使用这个类的话,需要在IDEA设置将generated-sources/annotations > Make Directory As Source Root, 或者在pom中添加build配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<id>test</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${basedir}/target/generated-sources/*</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>

参考:https://stackoverflow.com/questions/5170620/unable-to-use-intellij-with-a-generated-sources-folder

在生成java代码的时候可以使用javapoet,而不用傻瓜式一行行去写。

更详细的代码可以参考:https://github.com/gumingwei/apt-demo
基本的api可以参考:https://www.jianshu.com/p/50d95fbf635c

3. 如何debug程序

可以参考: https://stackoverflow.com/questions/8587096/how-do-you-debug-java-annotation-processors-using-intellij

1
2
3
4
5
public static void main(String[] args) throws Exception {
com.sun.tools.javac.Main.main(new String[] {"-proc:only",
"-processor", "io.patamon.apt.annotation.TestJavaSource",
"/Users/icemimosa/Documents/github/AskMisa/apt/apt-demo/src/main/java/io/patamon/apt/TestJavaSourceAnnotationDemo.java"});
}

其实内部就是调用了Java Compiler API

文章目录
  1. 1. 前言
  2. 2. 开始编码
    1. 2.1 定义注解
    2. 2.2 定义注解处理器
    3. 2.3 注册处理器服务
    4. 2.4 测试
  3. 3. 如何debug程序